package p.ithorns.sample.websocket.debugger;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import p.ithorns.framework.common.thread.ThreadPoolFactory;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * GateDebugTcpServer
 *
 * @author HtL
 * @date 2024/10/9 18:59
 * @since 1.0.0
 */
@Slf4j
public class DebugTcpServer {

    /**
     * 端口
     */
    private final int port = 9999;

    private NioEventLoopGroup bossGroup;

    private NioEventLoopGroup workerGroup;

    private volatile Channel serverChannel;

    private LocalChannelInitializer channelInitializer;

    private DebugTcpMsgHandler msgHandler;

    private Runnable callback;

    private volatile boolean running;

    /**
     * GATE
     */
    public final static ExecutorService DEBUG_THREAD
            = ThreadPoolFactory.createSinglePool("ws-debug-thread", new LinkedBlockingQueue<>(32));

    /**
     * 构造方法
     */
    private DebugTcpServer() {
        msgHandler = new DebugTcpMsgHandler();
    }


    /**
     * Holder单例
     */
    private static class Holder {
        private final static DebugTcpServer INSTANCE = new DebugTcpServer();
    }

    public static DebugTcpServer getInstance() {
        return Holder.INSTANCE;
    }


    public void setMsgHandler(DebugTcpMsgHandler msgHandler) {
        assert null != msgHandler;
        this.msgHandler = msgHandler;
    }

    public synchronized void init() {
        int coreSize = Runtime.getRuntime().availableProcessors();
        this.bossGroup = new NioEventLoopGroup(coreSize);
        this.workerGroup = new NioEventLoopGroup(coreSize + 1);
        this.channelInitializer = new LocalChannelInitializer(msgHandler);
        log.info("TCP server init...");
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup)
                .option(ChannelOption.SO_BACKLOG, 1024)
                //.childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE)
                .channel(NioServerSocketChannel.class)
                .childHandler(channelInitializer);

        // 启动
        try {
            serverChannel = b.bind(port).sync().channel();
            this.running = true;
            log.info("TCP server start on port：[{}]", port);

            // 回调
            if (null != callback) {
                callback.run();
            }
        } catch (InterruptedException e) {
            log.error("TcpServer thread has interrupted.", e);
            // Restore the interrupted status
            Thread.currentThread().interrupt();
        }
    }

    public synchronized void connect(Runnable callback) {
        this.callback = callback;
        if (!this.running) {
            // 没有运行，需要先启动
            this.start();
        } else {
            if (null != callback) {
                this.callback.run();
            }
        }
    }

    /**
     * 启动Netty服务
     *
     * @author 2020/2/23-11:45 by Ht.L
     */
    public synchronized void start() {
        DEBUG_THREAD.execute(this::init);
    }


    /**
     * 关闭Netty服务
     *
     * @author 2020/2/26-11:49 by Ht.L
     */
    public synchronized void stop() {
        if (null == serverChannel || (!serverChannel.isOpen() && !running)) {
            return;
        }

        serverChannel.close();
        workerGroup.shutdownGracefully();
        bossGroup.shutdownGracefully();
        try {
            workerGroup.terminationFuture().sync();
            bossGroup.terminationFuture().sync();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断状态
            log.error("Interrupted while waiting for event loop groups to terminate", e);
        }

        this.running = false;
        log.info("TCP server stopped.");
    }

    @ChannelHandler.Sharable
    static class LocalChannelInitializer extends ChannelInitializer<SocketChannel> {

        private ChannelHandler handler;

        LocalChannelInitializer() {
        }

        LocalChannelInitializer(ChannelHandler handler) {
            this.handler = handler;
        }

        public synchronized void setHandler(ChannelHandler handler) {
            this.handler = handler;
        }

        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ChannelInboundHandler tcpDecoder = new StringDecoder();
            ChannelOutboundHandler tcpEncoder = new StringEncoder();
//            ChannelInboundHandler tcpInboundHandler = new MsgInboundHandler();
//            ChannelInboundHandler exceptionHandler = new ExceptionHandler();

            // log.warn("建立新连接...{}", ch);
            ChannelPipeline pipeline = ch.pipeline();
            pipeline  //
                    // log
                    //.addLast("logging", new LoggingHandler(LogLevel.INFO))
                    // 心跳检测 注意执行顺序 需要放在前面
                    .addLast(new IdleStateHandler(60, 5, 0, TimeUnit.SECONDS))
                    //.addLast(new HeartBeatHandler())
                    .addLast(tcpDecoder)
                    .addLast(handler)
                    .addLast(tcpEncoder);

            // 异常管理
            // .addLast("exception", exceptionHandler)
        }

    }

    public void shutdown() {
        DEBUG_THREAD.shutdown();
    }


}